package com.alinesno.cloud.common.facade.wrapper;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.domain.Specification;

public class RestWrapper extends Wrapper {

	private static final long serialVersionUID = 2286891850011652336L;

	private static final Logger log = LoggerFactory.getLogger(RestWrapper.class);
	private boolean isHasOrder = false;
	private boolean removeApplication = false ; 

	private List<Condition> condition = new ArrayList<Condition>();

	public RestWrapper eq(String column, Object params) {
		condition.add(new Condition(column, params));
		return this;
	}

	public boolean isHasOrder() {
		for(Condition d : condition) {
			if(ORDER_BY.equals(d.getCondition())) {
				isHasOrder = true ; 
				break ; 
			}
		}
		return isHasOrder;
	}

	public void setHasOrder(boolean isHasOrder) {
		this.isHasOrder = isHasOrder;
	}

	public List<Condition> getCondition() {
		return condition;
	}

	public RestWrapper setCondition(List<Condition> condition) {
		this.condition = condition;
		return this;
	}

	public RestWrapper where(String sqlWhere, Object... params) {

		return null;
	}

	public RestWrapper ne(String column, Object params) {
		condition.add(new Condition(NE, column, params));
		return this;
	}

	public RestWrapper allEq(Map<String, Object> params) {
		if (params != null) {
			for (String k : params.keySet()) {
				condition.add(new Condition(k, params.get(k)));
			}
		}
		return this;
	}

	public RestWrapper gt(String column, Object params) {
		condition.add(new Condition(GT, column, params));
		return this;
	}

	public RestWrapper ge(String column, Object params) {
		condition.add(new Condition(GE, column, params));
		return this;
	}

	public RestWrapper lt(String column, Object params) {
		condition.add(new Condition(LT, column, params));
		return this;
	}

	public RestWrapper le(String column, Object params) {
		condition.add(new Condition(LE, column, params));
		return this ;
	}

	public RestWrapper and(String sqlAnd, Object... params) {

		return null;
	}

	public RestWrapper andNew() {

		return null;
	}

	public RestWrapper andNew(String sqlAnd, Object... params) {

		return null;
	}

	public RestWrapper and(String column, String params) {

		return null;
	}

	public RestWrapper or(String column, String params) {

		return null;
	}

	public RestWrapper or(boolean condition, String sqlOr, Object... params) {

		return null;
	}

	public RestWrapper or(String sqlOr, Object... params) {

		return null;
	}

	public RestWrapper orNew() {

		return null;
	}

	public RestWrapper orNew(String sqlOr, Object... params) {

		return null;
	}

	public RestWrapper groupBy(String columns) {

		return null;
	}

	public RestWrapper having(String sqlHaving, Object... params) {

		return null;
	}

	public RestWrapper orderBy(String columns) {

		return null;
	}

	public RestWrapper orderBy(String columns, boolean isAsc) {
		condition.add(new Condition(Wrapper.ORDER_BY, columns, isAsc));
		this.setHasOrder(true);
		return this;
	}

	public RestWrapper like(String column, String value) {
		condition.add(new Condition(LIKE, column, value));
		return this ;
	}

	public RestWrapper notLike(String column, String value) {
		condition.add(new Condition(NOT_LIKE, column, value));
		return this ;
	}

	public RestWrapper like(String column, String value, String type) {
		condition.add(new Condition(LIKE, column, value));
		return this ;
	}

	public RestWrapper notLike(String column, String value, String type) {
		condition.add(new Condition(NOT_LIKE, column, value));
		return this ;
	}

	public RestWrapper isNotNull(String columns) {

		return null;
	}

	public RestWrapper isNull(String columns) {

		return null;
	}

	public RestWrapper exists(String value) {

		return null;
	}

	public RestWrapper notExists(String value) {

		return null;
	}

	public RestWrapper in(String column, String value) {

		return null;
	}

	public RestWrapper notIn(String column, String value) {
		condition.add(new Condition(Wrapper.NOT_IN, column, value));
		return this ;
	}

	public RestWrapper in(String column, Collection<?> value) {

		return null;
	}

	public RestWrapper notIn(String column, Collection<?> value) {

		return null;
	}

	public RestWrapper in(String column, Object[] value) {

		return null;
	}

	public RestWrapper notIn(String column, Object... value) {

		return null;
	}

	public RestWrapper between(String column, Object val1, Object val2) {

		return null;
	}

	public boolean isRemoveApplication() {
		return removeApplication;
	}

	public void setRemoveApplication(boolean removeApplication) {
		this.removeApplication = removeApplication;
	}

	public RestWrapper notBetween(String column, Object val1, Object val2) {

		return null;
	}

	public <T> Predicate toSelfPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {

		List<Predicate> predicates = new ArrayList<Predicate>();

		if (condition != null && condition.size() > 0) {
			for (Condition c : condition) {

				String conditionKey = c.getCondition();
				String column = c.getColumn();
				Object params = c.getParams();

				switch (conditionKey) {
				case EQ : predicates.add(criteriaBuilder.equal(root.get(column), params)); break;
				case NE : predicates.add(criteriaBuilder.notEqual(root.get(column), params)); break;
				case LIKE : predicates.add(criteriaBuilder.like(root.get(column), "%" + params + "%")); break;
				case NOT_LIKE : predicates.add(criteriaBuilder.notLike(root.get(column), "%" + params + "%")); break;
				case LIKE_LEFT : predicates.add(criteriaBuilder.like(root.get(column), "%" + params)); break;
				case LIKE_RIGHT : predicates.add(criteriaBuilder.like(root.get(column), params + "%")); break;
				case LE : predicates.add(criteriaBuilder.le(root.get(column), Double.parseDouble(params + ""))); break;
				case LT : predicates.add(criteriaBuilder.lt(root.get(column), Double.parseDouble(params + ""))); break;
				case LETIME : predicates.add(criteriaBuilder.greaterThan(root.<Date>get(column), parseDate(params + ""))); break;
				case LTTIME : predicates.add(criteriaBuilder.lessThan(root.<Date>get(column), parseDate(params + ""))); break;
				case GE : predicates.add(criteriaBuilder.ge(root.get(column), Double.parseDouble(params + ""))); break;
				case GT : predicates.add(criteriaBuilder.gt(root.get(column), Double.parseDouble(params + ""))); break;
				case GETIME : predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.<Date>get(column), parseDate(params + ""))); break;
				case GTTIME : predicates.add(criteriaBuilder.lessThanOrEqualTo(root.<Date>get(column), parseDate(params + ""))); break;
				case ORDER_BY : query.orderBy(Boolean.parseBoolean(params + "") ? criteriaBuilder.asc(root.get(column)): criteriaBuilder.desc(root.get(column))); break;
				default: predicates.add(criteriaBuilder.equal(root.<Object>get(column), params)); break;
				}
			}
		}

		return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
	}

	@SuppressWarnings("serial")
	public <T> Specification<T> toSpecification() {

		Specification<T> spec = new Specification<T>() {
			@Override
			public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
				return toSelfPredicate(root, query, criteriaBuilder);
			}

		};

		return spec;
	}

	/**
	 * 网页时间格式化
	 * @param inputDate
	 * @return
	 */
	private static Date parseDate(String inputDate) {
        Date outputDate = null;
        String[] possibleDateFormats =
                {
                        "yyyy-MM-dd",
                        "yyyyMMdd",
                        "yyyy/MM/dd",
                        "yyyy年MM月dd日",
                        "yyyy MM dd"
                };
 
        try {
            outputDate = DateUtils.parseDate(inputDate, possibleDateFormats);
        } catch (ParseException e) {
        	log.error("时间【"+inputDate+"】格式化错误:" + e);
        }
        return outputDate;
    }

	/**
	 * 条件转换
	 * 
	 * @param c 前端传递参数
	 */
	public void builderCondition(Map<String, Object> c) {
		if (c != null) {
			if (condition != null) {
				Iterator<Map.Entry<String, Object>> iterator = c.entrySet().iterator();
				while (iterator.hasNext()) {
					Map.Entry<String, Object> me = iterator.next();
					String[] keys = me.getKey().trim().split("\\|");
					Object value = me.getValue();

					if (StringUtils.isBlank(keys[0]) || value == null || StringUtils.isBlank("" + value)) {
						continue;
					}
					Condition condition = new Condition();
					if (keys.length == 1) { // 条件
						condition.setCondition("eq");
						condition.setColumn(keys[0]);
						condition.setParams(String.valueOf(me.getValue()));
					} else if (keys.length >= 2) { // 条件 
						condition.setCondition(keys[1]);
						condition.setColumn(keys[0]);
						condition.setParams(String.valueOf(me.getValue()));
					}
					this.condition.add(condition);
				}
			}
		}
	}

	public static RestWrapper create() {
		return new RestWrapper() ;
	}

	@Override
	public String toString() {
		return "RestWrapper [isHasOrder=" + isHasOrder + ", removeApplication=" + removeApplication + ", condition=" + condition + "]";
	}

}
